﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Castle.DynamicProxy;
using System.Linq.Expressions;
using System.Reflection;
using JackyCode.Mock.Extensions;
using JackyCode.Mock.Exceptions;

namespace JackyCode.Mock
{
    public class Mock<TEntity> where TEntity:class
    {
        private TEntity mockObject;

        private ProxyGenerator proxyGenerator = new ProxyGenerator();

        public IMockData MockData {get; set; }

        public IMockObjectFactory<TEntity> MockObjectFactory {get; set;}

        public Mock()
        {
            this.MockData = new MockDataImpl();
            this.MockObjectFactory = new MockObjectFactoryImpl<TEntity>(new MockInterceptorImpl(MockData));
        }

        public Mock(IMockData mockData, IMockObjectFactory<TEntity> mockObjectFactory)
        {
            this.MockData = mockData;
            this.MockObjectFactory = mockObjectFactory;
        }

        public TEntity Object
        {
            get
            {
                if (mockObject == null)
                {
                    mockObject = MockObjectFactory.CreateObject();
                }
                return mockObject;
            }
        }

        public ISetUp<TResult> SetUp<TResult>(Expression<Func<TEntity, TResult>> expression)
        {
            MockData.Merge(expression.ExtractAsMethodData(), null);
            return new SetUpImpl<TEntity, TResult>(expression, MockData);
        }

        public void Verify<TResult>(Expression<Func<TEntity, TResult>> expression)
        {
            if (MockData.GetExecuteTimes(expression.ExtractAsMethodData()) == 0)
            {
                throw new MockException("The method never excuted!");
            }
        }

        public void Verify<TResult>(Expression<Func<TEntity, TResult>> expression,int times)
        {
            int actualExecTimes = MockData.GetExecuteTimes(expression.ExtractAsMethodData());
            if (!actualExecTimes.Equals(times))
            {
                throw new MockException(string.Format("Except times:{0},but actual times:{1}",times,actualExecTimes));
            }
        }

    }
}
